home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / daemons / lprm_fix.z / lprm_fix / lpr / common_source / printcap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-04  |  9.5 KB  |  445 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)printcap.c    5.7 (Berkeley) 3/4/91";
  36. #endif /* not lint */
  37.  
  38. #include <ctype.h>
  39. #include <stdio.h>
  40. #include "pathnames.h"
  41.  
  42. #ifndef BUFSIZ
  43. #define    BUFSIZ    1024
  44. #endif
  45. #define MAXHOP    32    /* max number of tc= indirections */
  46.  
  47. /*
  48.  * termcap - routines for dealing with the terminal capability data base
  49.  *
  50.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  51.  *        for capabilities alphabetically would not be a n**2/2
  52.  *        process when large numbers of capabilities are given.
  53.  * Note:    If we add a last pointer now we will screw up the
  54.  *        tc capability. We really should compile termcap.
  55.  *
  56.  * Essentially all the work here is scanning and decoding escapes
  57.  * in string capabilities.  We don't use stdio because the editor
  58.  * doesn't, and because living w/o it is not hard.
  59.  */
  60.  
  61. #define PRINTCAP
  62.  
  63. #ifdef PRINTCAP
  64. #define tgetent    pgetent
  65. #define tskip    pskip
  66. #define tgetstr    pgetstr
  67. #define tdecode pdecode
  68. #define tgetnum    pgetnum
  69. #define    tgetflag pgetflag
  70. #define tdecode pdecode
  71. #define tnchktc    pnchktc
  72. #define    tnamatch pnamatch
  73. #define V6
  74. #endif
  75.  
  76. static    FILE *pfp = NULL;    /* printcap data base file pointer */
  77. static    char *tbuf;
  78. static    int hopcount;        /* detect infinite loops in termcap, init 0 */
  79. char    *tskip();
  80. char    *tgetstr();
  81. char    *tdecode();
  82. char    *getenv();
  83.  
  84. /*
  85.  * Similar to tgetent except it returns the next enrty instead of
  86.  * doing a lookup.
  87.  */
  88. getprent(bp)
  89.     register char *bp;
  90. {
  91.     register int c, skip = 0;
  92.  
  93.     if (pfp == NULL && (pfp = fopen(_PATH_PRINTCAP, "r")) == NULL)
  94.         return(-1);
  95.     tbuf = bp;
  96.     for (;;) {
  97.         switch (c = getc(pfp)) {
  98.         case EOF:
  99.             fclose(pfp);
  100.             pfp = NULL;
  101.             return(0);
  102.         case '\n':
  103.             if (bp == tbuf) {
  104.                 skip = 0;
  105.                 continue;
  106.             }
  107.             if (bp[-1] == '\\') {
  108.                 bp--;
  109.                 continue;
  110.             }
  111.             *bp = '\0';
  112.             return(1);
  113.         case '#':
  114.             if (bp == tbuf)
  115.                 skip++;
  116.         default:
  117.             if (skip)
  118.                 continue;
  119.             if (bp >= tbuf+BUFSIZ) {
  120.                 write(2, "Termcap entry too long\n", 23);
  121.                 *bp = '\0';
  122.                 return(1);
  123.             }
  124.             *bp++ = c;
  125.         }
  126.     }
  127. }
  128.  
  129. endprent()
  130. {
  131.     if (pfp != NULL)
  132.         fclose(pfp);
  133. }
  134.  
  135. /*
  136.  * Get an entry for terminal name in buffer bp,
  137.  * from the termcap file.  Parse is very rudimentary;
  138.  * we just notice escaped newlines.
  139.  */
  140. tgetent(bp, name)
  141.     char *bp, *name;
  142. {
  143.     register char *cp;
  144.     register int c;
  145.     register int i = 0, cnt = 0;
  146.     char ibuf[BUFSIZ];
  147.     char *cp2;
  148.     int tf;
  149.  
  150.     tbuf = bp;
  151.     tf = 0;
  152. #ifndef V6
  153.     cp = getenv("TERMCAP");
  154.     /*
  155.      * TERMCAP can have one of two things in it. It can be the
  156.      * name of a file to use instead of /etc/termcap. In this
  157.      * case it better start with a "/". Or it can be an entry to
  158.      * use so we don't have to read the file. In this case it
  159.      * has to already have the newlines crunched out.
  160.      */
  161.     if (cp && *cp) {
  162.         if (*cp!='/') {
  163.             cp2 = getenv("TERM");
  164.             if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  165.                 strcpy(bp,cp);
  166.                 return(tnchktc());
  167.             } else {
  168.                 tf = open(_PATH_PRINTCAP, 0);
  169.             }
  170.         } else
  171.             tf = open(cp, 0);
  172.     }
  173.     if (tf==0)
  174.         tf = open(_PATH_PRINTCAP, 0);
  175. #else
  176.     tf = open(_PATH_PRINTCAP, 0);
  177. #endif
  178.     if (tf < 0)
  179.         return (-1);
  180.     for (;;) {
  181.         cp = bp;
  182.         for (;;) {
  183.             if (i == cnt) {
  184.                 cnt = read(tf, ibuf, BUFSIZ);
  185.                 if (cnt <= 0) {
  186.                     close(tf);
  187.                     return (0);
  188.                 }
  189.                 i = 0;
  190.             }
  191.             c = ibuf[i++];
  192.             if (c == '\n') {
  193.                 if (cp > bp && cp[-1] == '\\'){
  194.                     cp--;
  195.                     continue;
  196.                 }
  197.                 break;
  198.             }
  199.             if (cp >= bp+BUFSIZ) {
  200.                 write(2,"Termcap entry too long\n", 23);
  201.                 break;
  202.             } else
  203.                 *cp++ = c;
  204.         }
  205.         *cp = 0;
  206.  
  207.         /*
  208.          * The real work for the match.
  209.          */
  210.         if (tnamatch(name)) {
  211.             close(tf);
  212.             return(tnchktc());
  213.         }
  214.     }
  215. }
  216.  
  217. /*
  218.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  219.  * recursively find xxx and append that entry (minus the names)
  220.  * to take the place of the tc=xxx entry. This allows termcap
  221.  * entries to say "like an HP2621 but doesn't turn on the labels".
  222.  * Note that this works because of the left to right scan.
  223.  */
  224. tnchktc()
  225. {
  226.     register char *p, *q;
  227.     char tcname[16];    /* name of similar terminal */
  228.     char tcbuf[BUFSIZ];
  229.     char *holdtbuf = tbuf;
  230.     int l;
  231.  
  232.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  233.     while (*--p != ':')
  234.         if (p<tbuf) {
  235.             write(2, "Bad termcap entry\n", 18);
  236.             return (0);
  237.         }
  238.     p++;
  239.     /* p now points to beginning of last field */
  240.     if (p[0] != 't' || p[1] != 'c')
  241.         return(1);
  242.     strcpy(tcname,p+3);
  243.     q = tcname;
  244.     while (q && *q != ':')
  245.         q++;
  246.     *q = 0;
  247.     if (++hopcount > MAXHOP) {
  248.         write(2, "Infinite tc= loop\n", 18);
  249.         return (0);
  250.     }
  251.     if (tgetent(tcbuf, tcname) != 1)
  252.         return(0);
  253.     for (q=tcbuf; *q != ':'; q++)
  254.         ;
  255.     l = p - holdtbuf + strlen(q);
  256.     if (l > BUFSIZ) {
  257.         write(2, "Termcap entry too long\n", 23);
  258.         q[BUFSIZ - (p-tbuf)] = 0;
  259.     }
  260.     strcpy(p, q+1);
  261.     tbuf = holdtbuf;
  262.     return(1);
  263. }
  264.  
  265. /*
  266.  * Tnamatch deals with name matching.  The first field of the termcap
  267.  * entry is a sequence of names separated by |'s, so we compare
  268.  * against each such name.  The normal : terminator after the last
  269.  * name (before the first field) stops us.
  270.  */
  271. tnamatch(np)
  272.     char *np;
  273. {
  274.     register char *Np, *Bp;
  275.  
  276.     Bp = tbuf;
  277.     if (*Bp == '#')
  278.         return(0);
  279.     for (;;) {
  280.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  281.             continue;
  282.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  283.             return (1);
  284.         while (*Bp && *Bp != ':' && *Bp != '|')
  285.             Bp++;
  286.         if (*Bp == 0 || *Bp == ':')
  287.             return (0);
  288.         Bp++;
  289.     }
  290. }
  291.  
  292. /*
  293.  * Skip to the next field.  Notice that this is very dumb, not
  294.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  295.  * into the termcap file in octal.
  296.  */
  297. static char *
  298. tskip(bp)
  299.     register char *bp;
  300. {
  301.  
  302.     while (*bp && *bp != ':')
  303.         bp++;
  304.     if (*bp == ':')
  305.         bp++;
  306.     return (bp);
  307. }
  308.  
  309. /*
  310.  * Return the (numeric) option id.
  311.  * Numeric options look like
  312.  *    li#80
  313.  * i.e. the option string is separated from the numeric value by
  314.  * a # character.  If the option is not found we return -1.
  315.  * Note that we handle octal numbers beginning with 0.
  316.  */
  317. tgetnum(id)
  318.     char *id;
  319. {
  320.     register int i, base;
  321.     register char *bp = tbuf;
  322.  
  323.     for (;;) {
  324.         bp = tskip(bp);
  325.         if (*bp == 0)
  326.             return (-1);
  327.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  328.             continue;
  329.         if (*bp == '@')
  330.             return(-1);
  331.         if (*bp != '#')
  332.             continue;
  333.         bp++;
  334.         base = 10;
  335.         if (*bp == '0')
  336.             base = 8;
  337.         i = 0;
  338.         while (isdigit(*bp))
  339.             i *= base, i += *bp++ - '0';
  340.         return (i);
  341.     }
  342. }
  343.  
  344. /*
  345.  * Handle a flag option.
  346.  * Flag options are given "naked", i.e. followed by a : or the end
  347.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  348.  * not given.
  349.  */
  350. tgetflag(id)
  351.     char *id;
  352. {
  353.     register char *bp = tbuf;
  354.  
  355.     for (;;) {
  356.         bp = tskip(bp);
  357.         if (!*bp)
  358.             return (0);
  359.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  360.             if (!*bp || *bp == ':')
  361.                 return (1);
  362.             else if (*bp == '@')
  363.                 return(0);
  364.         }
  365.     }
  366. }
  367.  
  368. /*
  369.  * Get a string valued option.
  370.  * These are given as
  371.  *    cl=^Z
  372.  * Much decoding is done on the strings, and the strings are
  373.  * placed in area, which is a ref parameter which is updated.
  374.  * No checking on area overflow.
  375.  */
  376. char *
  377. tgetstr(id, area)
  378.     char *id, **area;
  379. {
  380.     register char *bp = tbuf;
  381.  
  382.     for (;;) {
  383.         bp = tskip(bp);
  384.         if (!*bp)
  385.             return (0);
  386.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  387.             continue;
  388.         if (*bp == '@')
  389.             return(0);
  390.         if (*bp != '=')
  391.             continue;
  392.         bp++;
  393.         return (tdecode(bp, area));
  394.     }
  395. }
  396.  
  397. /*
  398.  * Tdecode does the grung work to decode the
  399.  * string capability escapes.
  400.  */
  401. static char *
  402. tdecode(str, area)
  403.     register char *str;
  404.     char **area;
  405. {
  406.     register char *cp;
  407.     register int c;
  408.     register char *dp;
  409.     int i;
  410.  
  411.     cp = *area;
  412.     while ((c = *str++) && c != ':') {
  413.         switch (c) {
  414.  
  415.         case '^':
  416.             c = *str++ & 037;
  417.             break;
  418.  
  419.         case '\\':
  420.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  421.             c = *str++;
  422. nextc:
  423.             if (*dp++ == c) {
  424.                 c = *dp++;
  425.                 break;
  426.             }
  427.             dp++;
  428.             if (*dp)
  429.                 goto nextc;
  430.             if (isdigit(c)) {
  431.                 c -= '0', i = 2;
  432.                 do
  433.                     c <<= 3, c |= *str++ - '0';
  434.                 while (--i && isdigit(*str));
  435.             }
  436.             break;
  437.         }
  438.         *cp++ = c;
  439.     }
  440.     *cp++ = 0;
  441.     str = *area;
  442.     *area = cp;
  443.     return (str);
  444. }
  445.